﻿using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

namespace DldUtil
{
    public static class GetRspDefines
    {
        static string SmcsFilePath
        {
            get { return Application.dataPath + "/smcs.rsp"; }
        }

        static string McsFilePath
        {
            get { return Application.dataPath + "/mcs.rsp"; }
        }

        static string UsFilePath
        {
            get { return Application.dataPath + "/us.rsp"; }
        }

        static string BooFilePath
        {
            get { return Application.dataPath + "/boo.rsp"; }
        }

        public struct Entry
        {
            public int TimesDefinedInSmcs;
            public int TimesDefinedInMcs;
            public int TimesDefinedInUs;
            public int TimesDefinedInBoo;
            public int TimesDefinedInBuiltIn;
        }

        // Unity-made defines are in EditorUserBuildSettings.activeScriptCompilationDefines
        static bool IsDefineAlreadyInUnity(string defineName)
        {
            string[] builtInDefines = EditorUserBuildSettings.activeScriptCompilationDefines;

            for (int n = 0, len = builtInDefines.Length; n < len; n++)
            {
                if (builtInDefines[n] == defineName)
                {
                    return true;
                }
            }

            return false;
        }

        // ========================================================================================

        static void IncrementTimesDefinedInBuiltIn(Dictionary<string, Entry> table, string define)
        {
            if (!table.ContainsKey(define))
            {
                table[define] = new Entry();
            }

            Entry currentDef = table[define];
            currentDef.TimesDefinedInBuiltIn++;

            // assign it back to store it
            table[define] = currentDef;
        }

        static void IncrementTimesDefinedInSmcs(Dictionary<string, Entry> table, string define)
        {
            if (!table.ContainsKey(define))
            {
                table[define] = new Entry();
            }

            Entry currentDef = table[define];
            currentDef.TimesDefinedInSmcs++;

            // assign it back to store it
            table[define] = currentDef;
        }

        static void IncrementTimesDefinedInMcs(Dictionary<string, Entry> table, string define)
        {
            if (!table.ContainsKey(define))
            {
                table[define] = new Entry();
            }

            Entry currentDef = table[define];
            currentDef.TimesDefinedInMcs++;

            // assign it back to store it
            table[define] = currentDef;
        }

        static void IncrementTimesDefinedInUs(Dictionary<string, Entry> table, string define)
        {
            if (!table.ContainsKey(define))
            {
                table[define] = new Entry();
            }

            Entry currentDef = table[define];
            currentDef.TimesDefinedInUs++;

            // assign it back to store it
            table[define] = currentDef;
        }

        static void IncrementTimesDefinedInBoo(Dictionary<string, Entry> table, string define)
        {
            if (!table.ContainsKey(define))
            {
                table[define] = new Entry();
            }

            Entry currentDef = table[define];
            currentDef.TimesDefinedInBoo++;

            // assign it back to store it
            table[define] = currentDef;
        }

        // ========================================================================================

        public static Dictionary<string, Entry> GetDefines()
        {
            Dictionary<string, Entry> result = new Dictionary<string, Entry>();

            // ---------------------------------------------------------

            string[] definesInSmcs = GetDefinesInsideFile(SmcsFilePath);

            if (definesInSmcs != null && definesInSmcs.Length > 0)
            {
                for (int n = 0, len = definesInSmcs.Length; n < len; n++)
                {
                    IncrementTimesDefinedInSmcs(result, definesInSmcs[n]);
                    if (IsDefineAlreadyInUnity(definesInSmcs[n]))
                    {
                        IncrementTimesDefinedInBuiltIn(result, definesInSmcs[n]);
                    }
                }
            }

            // ---------------------------------------------------------

            string[] definesInMcs = GetDefinesInsideFile(McsFilePath);

            if (definesInMcs != null && definesInMcs.Length > 0)
            {
                for (int n = 0, len = definesInMcs.Length; n < len; n++)
                {
                    IncrementTimesDefinedInMcs(result, definesInMcs[n]);
                    if (IsDefineAlreadyInUnity(definesInMcs[n]))
                    {
                        IncrementTimesDefinedInBuiltIn(result, definesInMcs[n]);
                    }
                }
            }

            // ---------------------------------------------------------

            string[] definesInUs = GetDefinesInsideFile(UsFilePath);

            if (definesInUs != null && definesInUs.Length > 0)
            {
                for (int n = 0, len = definesInUs.Length; n < len; n++)
                {
                    IncrementTimesDefinedInUs(result, definesInUs[n]);
                    if (IsDefineAlreadyInUnity(definesInUs[n]))
                    {
                        IncrementTimesDefinedInBuiltIn(result, definesInUs[n]);
                    }
                }
            }

            // ---------------------------------------------------------

            string[] definesInBoo = GetDefinesInsideFile(BooFilePath);

            if (definesInBoo != null && definesInBoo.Length > 0)
            {
                for (int n = 0, len = definesInBoo.Length; n < len; n++)
                {
                    IncrementTimesDefinedInBoo(result, definesInBoo[n]);
                    if (IsDefineAlreadyInUnity(definesInBoo[n]))
                    {
                        IncrementTimesDefinedInBuiltIn(result, definesInBoo[n]);
                    }
                }
            }

            // ---------------------------------------------------------

            return result;
        }

        static string[] GetDefinesInsideFile(string filePath)
        {
            if (!File.Exists(filePath))
            {
                return null;
            }

            string rawContents = File.ReadAllText(filePath);
            if (!rawContents.StartsWith("-define:"))
            {
                // malformed .rsp file
                return null;
            }

            // remove "-define:"
            string allDefines = rawContents.Substring(8);
            //Debug.Log(allDefines);

            return allDefines.Split(';');
        }
    }
}
